package cn.stylefeng.guns.modular.gridsystem.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.factory.PageFactory;
import cn.stylefeng.guns.core.pojo.page.PageResult;
import cn.stylefeng.guns.modular.gridsystem.entity.*;
import cn.stylefeng.guns.modular.gridsystem.enums.LogExceptionEnum;
import cn.stylefeng.guns.modular.gridsystem.enums.SystemParamExceptionEnum;
import cn.stylefeng.guns.modular.gridsystem.mapper.BizDeviceMapper;
import cn.stylefeng.guns.modular.gridsystem.mapper.BizExceptionMapper;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizDeviceParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizDeviceStatusAssessParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizExceptionParam;
import cn.stylefeng.guns.modular.gridsystem.model.result.BizDeviceExceptionRecordResult;
import cn.stylefeng.guns.modular.gridsystem.model.result.BizDeviceResult;
import cn.stylefeng.guns.modular.gridsystem.model.result.DeviceStatusNumberResult;
import cn.stylefeng.guns.modular.gridsystem.service.*;
import cn.stylefeng.guns.modular.gridsystem.utils.OptionalBean;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备表 服务实现类
 *
 * @author ssy
 * @date 2021/09/14 11:47
 */
@Slf4j
@Service
public class BizDeviceServiceImpl extends ServiceImpl<BizDeviceMapper, BizDevice> implements BizDeviceService {
    @Resource
    private BizExceptionService bizExceptionService;
    @Resource
    private BizDeviceStatusAssessService bizDeviceStatusAssessService;
    @Resource
    private BizStationService bizStationService;
    @Resource
    private BizGatewayChannelService bizGatewayChannelService;
    @Resource
    private BizGatewayService bizGatewayService;
    @Resource
    private BizGatewayTypeService bizGatewayTypeService;
    @Resource
    private BizExceptionMapper exceptionMapper;


    /**
     * 分页查询设备表
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<BizDeviceResult> page(BizDeviceParam param) {
        // 构造条件
        LambdaQueryWrapper<BizDevice> queryWrapper = new LambdaQueryWrapper<BizDevice>()
                .eq(ObjectUtil.isNotEmpty(param.getStationId()), BizDevice::getStationId, param.getStationId())
                .eq(ObjectUtil.isEmpty(param.getStationId()), BizDevice::getStationId, 0)
                .eq(ObjectUtil.isNotEmpty(param.getIndustryId()), BizDevice::getIndustryId, param.getIndustryId())
                .orderByDesc(BizDevice::getCreatedAt);
        // 查询分页结果
        return new PageResult<>(baseMapper.pageList(PageFactory.defaultPage(), queryWrapper));
    }

    /**
     * 查询所有设备表
     *
     * @param param 查询入参
     *              stationId 站点id
     *              id        主键id
     * @return
     */
    @Override
    public List<BizDeviceResult> list(BizDeviceParam param) {
        // 构造条件
        LambdaQueryWrapper<BizDevice> queryWrapper = new LambdaQueryWrapper<BizDevice>()
                .eq(ObjectUtil.isNotEmpty(param.getStationId()), BizDevice::getStationId, param.getStationId())
                .eq(ObjectUtil.isNotEmpty(param.getId()), BizDevice::getId, param.getId());
        return this.list(queryWrapper)
                .stream()
                .map(item -> BeanUtil.toBean(item, BizDeviceResult.class))
                .collect(Collectors.toList());
    }

    /**
     * 新增设备
     *
     * @param bizDeviceParam 新增设备入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(BizDeviceParam bizDeviceParam) {
        // 将dto转为实体
        BizDevice bizDevice = new BizDevice();
        BeanUtil.copyProperties(bizDeviceParam, bizDevice);
        save(bizDevice);
    }

    /**
     * 删除设备故障日志和设备评估日志
     *
     * @param bizDeviceParam 删除入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(BizDeviceParam bizDeviceParam) {
        OptionalBean.ofNullable(bizDeviceParam).orElseThrow(() -> new ServiceException(SystemParamExceptionEnum.PARAM_NULL_ERROR));
        OptionalBean.ofStr(bizDeviceParam.getId());
        //删除设备对应故障日志
        final BizExceptionParam bizExceptionParam = new BizExceptionParam();
        bizExceptionParam.setDeviceId(bizDeviceParam.getId());
        bizExceptionService.delete(bizExceptionParam);
        //删除设备对应的设备状态评估日志
        final BizDeviceStatusAssessParam deviceStatusAssessParam = new BizDeviceStatusAssessParam();
        deviceStatusAssessParam.setDeviceId(bizDeviceParam.getId());
        final List<BizDeviceStatusAssess> assessList = bizDeviceStatusAssessService.list(deviceStatusAssessParam);
        assessList.forEach(bizDeviceStatusAssess -> {
            final BizDeviceStatusAssessParam statusAssessParam = new BizDeviceStatusAssessParam();
            statusAssessParam.setId(bizDeviceStatusAssess.getId());
            statusAssessParam.setDeviceId(bizDeviceStatusAssess.getDeviceId());
            bizDeviceStatusAssessService.delete(statusAssessParam);
        });
        removeById(bizDeviceParam.getId());
    }

    /**
     * 修改设备信息
     *
     * @param bizDeviceParam 设备修改信息入参
     */
    @Override
    public void edit(BizDeviceParam bizDeviceParam) {
        // 根据id查询实体
        final BizDevice bizDevice = new BizDevice();
        // 请求参数转化为实体
        BeanUtil.copyProperties(bizDeviceParam, bizDevice);
        updateById(bizDevice);
    }

    /**
     * 根据id查询设备详情
     *
     * @param bizDeviceParam
     * @return
     */
    @Override
    public BizDeviceResult detail(BizDeviceParam bizDeviceParam) {
        return queryBizDevice(bizDeviceParam);
    }


    /**
     * 查询设备异常信息
     *
     * @param stationId id
     * @param startTime 查询开始时间
     * @param endTime   查询结束时间
     * @return List<BizDeviceExceptionRecordResult>
     */
    @Override
    public List<BizDeviceExceptionRecordResult> getDeviceException(Integer stationId, String startTime, String endTime) {
        return baseMapper.getDeviceExecption(stationId, startTime, endTime);
    }


    /**
     * 获取设备表
     *
     * @param bizDeviceParam 查询入参
     *                       id      主键id
     * @return BizDeviceResult
     */
    private BizDeviceResult queryBizDevice(BizDeviceParam bizDeviceParam) {
        OptionalBean.ofNullable(bizDeviceParam).orElseThrow(() -> new ServiceException(SystemParamExceptionEnum.PARAM_NULL_ERROR));
        OptionalBean.ofStr(bizDeviceParam.getId());
        BizDevice bizDevice = getById(bizDeviceParam.getId());
        OptionalBean.ofNullable(bizDevice).orElseThrow(() -> new ServiceException(LogExceptionEnum.NOT_EXISTED));
        final BizDeviceResult bizDeviceResult = new BizDeviceResult();
        BeanUtil.copyProperties(bizDevice, bizDeviceResult);
        return bizDeviceResult;
    }

    /**
     * 根据当前用户查询电站和设备数量
     *
     * @param stationIds 电站id
     * @return Integer
     */
    @Override
    public Integer getCountByStationIds(String stationIds) {
        OptionalBean.ofStr(stationIds);
        final String[] split = stationIds.split(",");
        int count = 0;
        for (String stationId : split) {
            final LambdaQueryWrapper<BizDevice> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(BizDevice::getStationId, stationId);
            count += count(queryWrapper);
        }
        return count;
    }

    /**
     * 查询设备列表
     *
     * @param stationId 站点id
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> getAllListByStationId(Integer stationId) {
        OptionalBean.ofStr(stationId);
        LambdaQueryWrapper<BizDevice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BizDevice::getStationId, stationId);
        BizStation bizStation = bizStationService.getById(stationId);
        Map<String, Object> hashMap = MapUtil.newHashMap();
        hashMap.put("stationId", bizStation.getId());
        hashMap.put("stationName", bizStation.getStationName());
        hashMap.put("stationAddress", bizStation.getStationAddress());

        // todo 查询设备在线离线数量
        DeviceStatusNumberResult deviceOnlineNumber = bizGatewayService.getDeviceOnlineNumber(stationId);
        if (ObjectUtil.isNotNull(deviceOnlineNumber)) {
            hashMap.put("onlineNumber", deviceOnlineNumber.getOnlineNumber());
            hashMap.put("offlineNumber", deviceOnlineNumber.getOfflineNumber());
        }

        List<BizDevice> deviceList = this.list(queryWrapper);
        Map<Object, Object> deviceMap = MapUtil.newHashMap();
        for (BizDevice device : deviceList) {
            List<String> gatewayCodes = new ArrayList<>();
            Integer deviceId = device.getId();
            String deviceName = device.getDeviceName();
            LambdaQueryWrapper<BizGatewayChannel> channelQueryWrapper = new LambdaQueryWrapper<>();
            channelQueryWrapper.eq(BizGatewayChannel::getDeviceId, deviceId);
            List<BizGatewayChannel> channelList = bizGatewayChannelService.list(channelQueryWrapper);
            List<Map<String, Object>> mapList = new ArrayList<>();
            Set<Map<String, Object>> gateways = new HashSet<>();
            for (BizGatewayChannel gatewayChannel : channelList) {
                Integer gatewayId = gatewayChannel.getGatewayId();
                QueryWrapper<BizGateway> gatewayQueryWrapper = new QueryWrapper<>();
                gatewayQueryWrapper.select("id as gatewayId", "type_code as typeCode", "gateway_code as gatewayCode", "gateway_name as gatewayName");
                gatewayQueryWrapper.eq("id", gatewayId);
                Map<String, Object> gateway = bizGatewayService.getMap(gatewayQueryWrapper);
                if (ObjectUtil.isNotNull(gateway)) {
                    QueryWrapper<BizGatewayType> queryWrapper1 = new QueryWrapper<>();
                    queryWrapper1.eq("code", gateway.get("typeCode"));
                    BizGatewayType bizGatewayType = bizGatewayTypeService.getOne(queryWrapper1);
                    if (ObjectUtil.isNotNull(bizGatewayType)) {
                        gateway.put("fileName", bizGatewayType.getFileName());
                    }
                    gateways.add(gateway);
                }
                Map<String, Object> channelMap = new LinkedHashMap<>();
                channelMap.put("name", gateway.get("gatewayCode"));
                channelMap.put("micRouter", gatewayChannel.getChannel());
                channelMap.put("installLocation", gatewayChannel.getInstallLocation());
                mapList.add(channelMap);
            }
            HashMap<Object, Object> gatewayMap = MapUtil.newHashMap();
            gatewayMap.put("deviceName", deviceName);
            gatewayMap.put("deviceId", deviceId);
            gatewayMap.put("deviceFileName", device.getFileName());
            gatewayMap.put("gateway", gateways);
            gatewayMap.put("count", gateways.size());

            for (Map<String, Object> g : gateways) {
                gatewayCodes.add(g.get("gatewayCode").toString());
            }
            gatewayMap.put("channel", mapList);
            if (ObjectUtil.isNotEmpty(gatewayCodes)) {
                gatewayMap.put("hasNoHandleException", exceptionMapper.selectCount(new LambdaQueryWrapper<BizException>()
                        .in(BizException::getGatewayCode, gatewayCodes)
                        .eq(BizException::getStatus, "0")) > 0);
            } else {
                gatewayMap.put("hasNoHandleException", false);
            }
            deviceMap.put(deviceId, gatewayMap);
        }
        hashMap.put("device", deviceMap);
        return hashMap;
    }
}
